module Alchemy
  class PageTreeSerializer < BaseSerializer
    def attributes
      {'pages' => nil}
    end

    def pages
      tree = []
      path = [{id: object.parent_id, children: tree}]
      page_list = object.self_and_descendants
      skip_branch = false
      base_level = object.level - 1

      page_list.each_with_index do |page, i|
        has_children = page_list[i + 1] && page_list[i + 1].parent_id == page.id
        folded = has_children && page.folded?(opts[:user])

        if skip_branch
          next if page.parent_id == path.last[:children].last[:id]

          skip_branch = false
        end

        # Do not walk my children if I'm folded and you don't need to have the
        # full tree.
        if folded && !opts[:full]
          skip_branch = true
        end

        if page.parent_id != path.last[:id]
          if path.map { |o| o[:id] }.include?(page.parent_id) # Lower level
            path.pop while path.last[:id] != page.parent_id
          else # One level up
            path << path.last[:children].last
          end
        end

        level = path.count + base_level

        path.last[:children] << page_hash(page, has_children, level, folded)
      end

      tree
    end

    protected

    def page_hash(page, has_children, level, folded)
      {
        id: page.id,
        name: page.name,
        permissions: page_permissions(page, opts[:ability]),
        public: page.public?,
        visible: page.visible?,
        restricted: page.restricted?,
        status_titles: page_status_titles(page),
        page_layout: page.page_layout,
        slug: page.slug,
        redirects_to_external: page.redirects_to_external?,
        locked: page.locked?,
        definition_missing: page.definition.blank?,
        urlname: page.urlname,
        external_urlname: page.external_urlname,
        level: level,
        root: level == 1,
        folded: folded,
        root_or_leaf: level == 1 || !has_children,
        children: []
      }
    end

    def page_permissions(page, ability)
      {
        info: ability.can?(:info, page),
        configure: ability.can?(:configure, page),
        copy: ability.can?(:copy, page),
        destroy: ability.can?(:destroy, page),
        create: ability.can?(:create, Alchemy::Page)
      }
    end

    def page_status_titles(page)
      {
        public: page.status_title(:public),
        visible: page.status_title(:visible),
        restricted: page.status_title(:restricted)
      }
    end
  end
end
